<!--
 * @Author: caisue
 * @version: V1.0.0
 * @Date: 2025-05-20 11:11:47
 * @LastEditors: caisue
 * @LastEditTime: 2025-05-30 09:01:21
 * @Descripttion: 
-->
<template>
  <div class="container">
    <div class="left-board">
      <el-scrollbar class="left-scrollbar">
        <div class="components-list">
          <div class="components-title">
            <svg-icon icon-class="component" />输入型组件
          </div>
          <draggable
            class="components-draggable"
            :list="inputComponents"
            :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
            :clone="cloneComponent"
            draggable=".components-item"
            :sort="false"
            @end="onEnd"
          >
            <div
              v-for="(element, index) in inputComponents" :key="index" class="components-item"
              @click="addComponent(element)"
            >
              <div class="components-body">
                <svg-icon :icon-class="element.tagIcon" />
                {{ element.label }}
              </div>
            </div>
          </draggable>
          <div class="components-title">
            <svg-icon icon-class="component" />选择型组件
          </div>
          <draggable
            class="components-draggable"
            :list="selectComponents"
            :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
            :clone="cloneComponent"
            draggable=".components-item"
            :sort="false"
            @end="onEnd"
          >
            <div
              v-for="(element, index) in selectComponents"
              :key="index"
              class="components-item"
              @click="addComponent(element)"
            >
              <div class="components-body">
                <svg-icon :icon-class="element.tagIcon" />
                {{ element.label }}
              </div>
            </div>
          </draggable>
          <div class="components-title">
            <svg-icon icon-class="component" /> 辅助组件
          </div>
          <draggable
            class="components-draggable" :list="assistantComponents"
            :group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent"
            draggable=".components-item" :sort="false" @end="onEnd"
          >
            <div
              v-for="(element, index) in assistantComponents" :key="index" class="components-item"
              @click="addComponent(element)"
            >
              <div class="components-body">
                <svg-icon :icon-class="element.tagIcon" />
                {{ element.label }}
              </div>
            </div>
          </draggable>
          <div class="components-title">
            <svg-icon icon-class="component" /> 布局型组件
          </div>
          <draggable
            class="components-draggable" :list="layoutComponents"
            :group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent"
            draggable=".components-item" :sort="false" @end="onEnd"
          >
              <div
                v-for="(element, index) in layoutComponents" :key="index" class="components-item"
                @click="addComponent(element)"
              >
                <div class="components-body">
                  <svg-icon :icon-class="element.tagIcon" />
                  {{ element.label }}
                </div>
              </div>
          </draggable>
        </div>
      </el-scrollbar>
    </div>

    <div class="center-board">
      <div class="action-bar">
         <el-button icon="el-icon-document" type="text" @click="$router.push('/detail')">
         去详情
        </el-button>
        <el-button icon="el-icon-download" type="text" @click="download">
          导出vue文件
        </el-button>
         <el-button icon="el-icon-document" type="text" @click="saveDrawingList">
          保存
        </el-button>
        <el-button class="copy-btn-main" icon="el-icon-document-copy" type="text" @click="copy">
          复制代码
        </el-button>
        <el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty">
          清空
        </el-button>
      </div>
      <el-scrollbar class="center-scrollbar">
        <el-row class="center-board-row" :gutter="formConf.gutter">
          <el-form
            :size="formConf.size"
            :label-position="formConf.labelPosition"
            :disabled="formConf.disabled"
            :label-width="formConf.labelWidth + 'px'"
          >
            <draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup" @end="onDrawEnd">
              <draggable-item
                v-for="(element, index) in drawingList"
                :key="element.renderKey"
                :drawing-list="drawingList"
                :element="element"
                :index="index"
                :active-id="activeId"
                :form-conf="formConf"
                @activeItem="activeFormItem"
                @copyItem="drawingItemCopy"
                @deleteItem="drawingItemDelete"
                @activeCell="drawingActiveCell"
              />
            </draggable>
            <div v-show="!drawingList.length" class="empty-info">
              从左侧拖入或点选组件进行表单设计
            </div>
          </el-form>
        </el-row>
      </el-scrollbar>
    </div>

    <right-panel
      :active-data="activeData"
      :form-conf="formConf"
      :show-field="!!drawingList.length"
      :activeCells="activeCells"
      @tag-change="tagChange"
    />

    <code-type-dialog
      :visible.sync="dialogVisible"
      title="选择生成类型"
      :show-file-name="showFileName"
      @confirm="generate"
    />
    <input id="copyNode" type="hidden">
  </div>
</template>

<script>
import draggable from 'vuedraggable'
import beautifier from 'js-beautify'
import ClipboardJS from 'clipboard'
import render from '@/utils/generator/render'
import RightPanel from './build/RightPanel'
import { inputComponents, selectComponents, layoutComponents, assistantComponents, formConf } from '@/utils/generator/config'
import { beautifierConf, titleCase } from '@/utils/index'
import { makeUpHtml, vueTemplate, vueScript, cssStyle } from '@/utils/generator/html'
import { makeUpJs } from '@/utils/generator/js'
import { makeUpCss } from '@/utils/generator/css'
import drawingDefault from '@/utils/generator/drawingDefault'
import CodeTypeDialog from './build/CodeTypeDialog'
import DraggableItem from './build/DraggableItem'
import _ from 'lodash'
let oldActiveId
let tempActiveData

export default { 
  components: {
    draggable,
    render,
    RightPanel,
    CodeTypeDialog,
    DraggableItem
  },
  data() {
    return {
      idGlobal: 100,
      formConf,
      inputComponents,
      selectComponents,
      layoutComponents,
      assistantComponents,
      labelWidth: 100,
      drawingList: drawingDefault,
      drawingData: {},
      activeId: drawingDefault[0].formId,
      drawerVisible: false,
      formData: {},
      dialogVisible: false,
      generateConf: null,
      showFileName: false,
      activeData: drawingDefault[0],
      parsedData: "",
      activeCells: null
    }
  },
  created() {
    // 防止 firefox 下 拖拽 会新打卡一个选项卡
    document.body.ondrop = event => {
      event.preventDefault()
      event.stopPropagation()
    }
  },
  watch: {
    // eslint-disable-next-line func-names
    'activeData.label': function (val, oldVal) {
      if (
        this.activeData.placeholder === undefined
        || !this.activeData.tag
        || oldActiveId !== this.activeId
      ) {
        this.$store.commit('setCurCellId', '')
        return
      }
      this.activeData.placeholder = this.activeData.placeholder.replace(oldVal, '') + val
    },
    activeId: {
      handler(val) {
        oldActiveId = val
      },
      immediate: true
    }
  },
  mounted() {
    const clipboard = new ClipboardJS('#copyNode', {
      text: trigger => {
        const codeStr = this.generateCode()
        this.$notify({
          title: '成功',
          message: '代码已复制到剪切板，可粘贴。',
          type: 'success'
        })
        return codeStr
      }
    })
    clipboard.on('error', e => {
      this.$message.error('代码复制失败')
    })
  },
  methods: {
    activeFormItem(element) {
      this.activeData = element
      this.activeId = element.formId
    },
    // 操作界面上的拖拽
    onDrawEnd(evt){
      // 获取当前拖拽的组件
      let curCellId = this.$store.state.curCellId
      if (curCellId) {
        let curItem = evt?.item?._underlying_vm_
        let _curItem = _.cloneDeep(curItem)
        _curItem.cellId = curCellId
        // 判断当前设计区域上已经存在当前组件，则先删除，再添加到单元格中
        this.drawingList = this.drawingList.filter(item => item.formId !== _curItem.formId)
        // 更新当前中间设计区域上的数据
        for (let i = 0; i < this.drawingList.length; i++) {
          const layouts = this.drawingList[i];
          if (layouts.layout === "tableCellItem") {
            layouts.children.push(_curItem)
          }
        }
      }
    },
    onEnd(obj, a) {
      if (obj.from !== obj.to) {
        // 处理从左侧拖拽时在表格和中间设计区域同时出现formId一致的情况
        // 若中间设计区域已经生成组件，则表格中的不再添加
        for (let k = 0; k < this.drawingList.length; k++) {
          const layout = this.drawingList[k];
          if (layout.formId === tempActiveData.formId) {
            this.$store.commit('setCurCellId', '')
            this.activeData = tempActiveData
            return
          }
        }
        // 当前操作的table布局
        let curTabelId = +obj.to.dataset.formid
        this.activeId = this.idGlobal
        let curCellId = this.$store.state.curCellId
        this.activeData = tempActiveData
        // 只有表格中才有
        if (curCellId) {
          // 更新当前中间设计区域上的数据
          for (let i = 0; i < this.drawingList.length; i++) {
            const layouts = this.drawingList[i];
            if (layouts.layout === "tableCellItem") {
              if (curTabelId === layouts.formId) {
                layouts.children.push({...tempActiveData, cellId: curCellId})
              }
            }
          }
        }
      }
    },
    addComponent(item) {
      const clone = this.cloneComponent(item)
      this.drawingList.push(clone)
      this.activeFormItem(clone)
    },
    cloneComponent(origin) {
      const clone = JSON.parse(JSON.stringify(origin))
      clone.formId = ++this.idGlobal
      clone.span = formConf.span
      clone.renderKey = +new Date() // 改变renderKey后可以实现强制更新组件
      if (!clone.layout) clone.layout = 'colFormItem' // 行容器
      if (clone.layout === 'colFormItem') { // 按钮
        clone.vModel = `field${this.idGlobal}`
        clone.placeholder !== undefined && (clone.placeholder += clone.label)
        tempActiveData = clone
        // 如果是文本组件和标题组件，则删除lable
        if (clone.tag === 'el-text' || clone.tag === 'el-title') {
          delete clone.label
        }
      } else if (clone.layout === 'rowFormItem') { // 行容器
        delete clone.label
        clone.componentName = `row${this.idGlobal}`
        clone.gutter = this.formConf.gutter
        tempActiveData = clone
      } else if (clone.layout === 'tableCellItem') { // 行容器
        clone.componentName = `table-cell${this.idGlobal}`
        clone.gutter = this.formConf.gutter
        clone.cellId = this.activeData.cellId // 绑定到当前激活的单元格
        tempActiveData = clone
      }
      return tempActiveData
    },
    AssembleFormData() {
      this.parsedData = this.drawingList
      this.formData = {
        fields: JSON.parse(JSON.stringify(this.drawingList)),
        ...this.formConf
      }
    },
    // confirm确定事件
    generate(data) {
      const func = this[`exec${titleCase(this.operationType)}`]
      this.generateConf = data
      func && func(data)
    },
    execRun(data) {
      this.AssembleFormData()
      this.drawerVisible = true
    },
    // 下载
    execDownload(data) {
      const codeStr = this.generateCode()
      const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
      this.$download.saveAs(blob, data.fileName)
    },
    execCopy(data) {
      document.getElementById('copyNode').click()
    },
    // TODO: 将修改的数据进行保存
    execSaveDrawingList(data) {
      console.log(data.fileName, 'this.drawingList~~~~', this.drawingList);
      this.parsedData = this.drawingList
      let needRexgArr = []
      for (let j = 0; j < this.drawingList.length; j++) {
        const ele = this.drawingList[j];
        // 是否是表格布局
        if (ele.tag === 'table-cell') {
           for (let s = 0; s < ele.children.length; s++) {
            const child = ele.children[s];
            if (child.required) {
              needRexgArr.push(child)
            }
          }
        } else {
          if (ele.required) {
            needRexgArr.push(ele)
          }
        }
      }
      console.log('needRexgArr~~~~~~~~~~',needRexgArr);
      this.needRexgList(needRexgArr)
      // $.ajax({
      //     url: 'http://25.215.193.85:18079/wpcommon-v1/sysTodoData/querySysUnifiedTodoData',
      //     type: 'post',
      //     dataType: 'json',
      //     data: JSON.stringify(this.parsedData),
      //     headers: {
      //         'Accept': 'application/json, text/javascript, */*; q=0.01',
      //         'Content-Type': 'application/json',
      //         'Authorization': 'token hhhhhh',
      //     },
      // }).then(res => {
      //   console.log(res, '==============================');
      // })
    },
    needRexgList(needRexgArr){
       for (let j = 0; j < needRexgArr.length; j++) {
        const item = needRexgArr[j];
        if (!item.defaultValue) {
          this.$message.warning(`${item.label}不能为空！`)
          return
        }
        for (let i = 0; i < item.regList.length; i++) {
          const _item = item.regList[i];
          let regex = new RegExp(_item.pattern.slice(1, -1))
          if (!regex.test(item.defaultValue)) {
            this.$message.warning(_item.message)
            return
          }
        }
      }
    },
    empty() {
      this.$confirm('确定要清空所有组件吗？', '提示', { type: 'warning' }).then(
        () => {
          this.drawingList = []
        }
      )
    },
    drawingItemCopy(item, parent) {
      let clone = JSON.parse(JSON.stringify(item))
      // 单元格中的组件
      if (clone.cellId) {
        for (let i = 0; i < this.drawingList.length; i++) {
          clone = this.createIdAndKey(clone)
           if (this.drawingList[i].layout === "tableCellItem") {
             this.drawingList[i].children.push(clone)
             this.activeFormItem(clone)
           }
        }
      } else {
        clone = this.createIdAndKey(clone)
        parent.push(clone)
        this.activeFormItem(clone)
      }
    },
    createIdAndKey(item) {
      item.formId = ++this.idGlobal
      item.renderKey = +new Date()
      // 按钮
      if (item.layout === 'colFormItem') {
        item.vModel = `field${this.idGlobal}`
        // 行容器
      } else if (item.layout === 'rowFormItem') {
        item.componentName = `row${this.idGlobal}`
        // 表格容器
      } else if (item.layout === 'tableCellItem') {
        item.componentName = `table-cell${this.idGlobal}`
      }
      // 下拉选择
      if (Array.isArray(item.children)) {
        item.children = item.children.map(childItem => this.createIdAndKey(childItem))
      }
      return item
    },
    // 删除
    drawingItemDelete(index, parent, item) {
      // 表格布局的单独处理
      if (item.cellId) {
        for (let i = 0; i < this.drawingList.length; i++) {
        const layouts = this.drawingList[i];
          layouts.children = layouts?.children?.filter(layout => layout.formId !== item.formId)
          this.$nextTick(() => {
            this.activeFormItem(this.drawingList)
          })
        }
      } else {
        parent.splice(index, 1)
        this.$nextTick(() => {
          const len = this.drawingList.length
          if (len) {
            this.activeFormItem(this.drawingList[len - 1])
          }
        })
      }
    },
    // 当前选中的单元格
    drawingActiveCell(item){
      if (!this.activeData?.tableData?.length) return
      for (let i = 0; i < this.activeData?.tableData?.length; i++) {
        const row = this.activeData.tableData[i];
        for (let j = 0; j < row.length; j++) {
          const cell = row[j];
          if (cell.id === item.id) {
            this.activeCells = row
          }
        }
      }
    },
    generateCode() {
      const { type } = this.generateConf
      this.AssembleFormData()
      const script = vueScript(makeUpJs(this.formData, type))
      const html = vueTemplate(makeUpHtml(this.formData, type))
      const css = cssStyle(makeUpCss(this.formData))
      return beautifier.html(html + script + css, beautifierConf.html)
    },
    download() {
      this.dialogVisible = true
      this.showFileName = true
      this.operationType = 'download'
    },
    run() {
      this.dialogVisible = true
      this.showFileName = false
      this.operationType = 'run'
    },
    copy() {
      this.dialogVisible = true
      this.showFileName = false
      this.operationType = 'copy'
    },
    saveDrawingList() {
      this.dialogVisible = true
      this.showFileName = true
      this.operationType = 'saveDrawingList'
    },
    tagChange(newTag) {
      newTag = this.cloneComponent(newTag)
      newTag.vModel = this.activeData.vModel
      newTag.formId = this.activeId
      newTag.span = this.activeData.span
      delete this.activeData.tag
      delete this.activeData.tagIcon
      delete this.activeData.document
      Object.keys(newTag).forEach(key => {
        if (this.activeData[key] !== undefined
          && typeof this.activeData[key] === typeof newTag[key]) {
          newTag[key] = this.activeData[key]
        }
      })
      this.activeData = newTag
      this.updateDrawingList(newTag, this.drawingList)
    },
    updateDrawingList(newTag, list) {
      const index = list.findIndex(item => item.formId === this.activeId)
      if (index > -1) {
        list.splice(index, 1, newTag)
      } else {
        list.forEach(item => {
          if (Array.isArray(item.children)) this.updateDrawingList(newTag, item.children)
        })
      }
    }
  }
}
</script>
